<?php
namespace App\Common\Cla\Com\Token;

use App\Common as com;
use App\Common\Cla\Com\Token as nameToken;

trait TraitKeyDbOperate{

	/**
	 * token对象
	 * @var nameToken
	 */
	protected $tokenObj = null;

	/**
	 * ApiToken->Session缓存键对象(使用时初始化，调用方法：$this->getTokenKeyDbObj())
	 * @var com\Lib\Cache\KeyDB
	 */
	private $_keyDbObj = null;

	/**
	 * 最后读取到的数据（缓存）
	 * @var array | null
	 */
	private $_lastKeyDbData = null;

	/**
	 * 最后读取到的数据的时间（缓存）
	 * @var int | null
	 */
	private $_lastKeyDbDataTime = null;

	/**
	 * [接口]获取Token->Session缓存键对象
	 * @return com\Lib\Cache\KeyDB
	 */
	public function keyDbObj(  ) {
		throw com\Lib\Err\Exception::makeOfNew( '接口未覆盖', com\Lib\Err\Code::$sysFunExecuteError );
	}

	/**
	 * 命令以秒为单位返回 key 的剩余过期时间。
	 * @return int 剩余过期时间。[-2]key不存在时 [-1]key 存在但没有设置剩余生存时间 [>=0]剩余过期时间
	 * @throws
	 */
	public function ttl(  ) {
		return $this->keyDbObj()->ttl();
	}

	/**
	 * 刷新数据时间
	 * @param int $expire 有效时间。[null]跟随原数据剩余时间 [>0]时间
	 * @return void
	 */
	public function refreshTtl( int $expire = null ) {
		$data = $this->get();
		// 数据不存在则不刷新
		if( $data !== false ){
			$this->set( $data, $expire ?? $this->tokenObj->data()->getSupTime() );
		}
	}

	/**
	 * 获取数据
	 * @param mixed $default 默认值。[false][默认]
	 * @return mixed 数据
	 */
	public function get( $default = false ) {
		return $this->keyDbObj()->get( $default );
	}

	/**
	 * 获取缓存数据
	 * @param int $cacheTimeS
	 * @return array
	 */
	public function getCache( $default = false, int $cacheTimeS = 5 ) {
		if( ! $this->cacheIsValid( $cacheTimeS ) ){
			$keyDbData = $this->get( $default );
			if( $default === $keyDbData ){
				return $default;
			}
			//
			$this->cacheSave( $keyDbData );
			//
			return $keyDbData;
		}else{
			return $this->_lastKeyDbData;
		}
	}

	/**
	 * 读取缓存
	 * @param string $keyDbPath 数据路径（支持格式：1.PHP数组访问的格式，如：['a'][0]['b']， 2."->"分割，如：a->b->c）。[null]获取所有数据
	 * @param mixed $default 默认值。[false]默认
	 * @param int $cacheTimeS 缓存有效时间。[5][默认]
	 * @return mixed|null
	 */
	public function getCacheOfPath( string $keyDbPath, $default = false, int $cacheTimeS = 5 ) {
		$keyDbData = $this->getCache( false, $cacheTimeS );
		if( $keyDbData === false ){
			return $default;
		}
		// 检查数据是否存在
		if( ! com\Lib\Fun\Array_::assignPathIsset( $keyDbData, $keyDbPath ) ){
			return $default;
		}
		//
		return com\Lib\Fun\Array_::assignPathRead( $keyDbData, $keyDbPath );
	}

	/**
	 * 读取(路径)
	 * @param string $keyDbPath 数组路径（支持格式：1.PHP数组访问的格式，如：['a'][0]['b']， 2."->"分割，如：a->b->c）。[null]获取所有数据
	 * @param mixed $default 默认值。[false][默认]
	 * @return mixed session数据
	 */
	public function getOfPath( string $keyDbPath, $default = false ) {
		return $this->keyDbObj()->getOfPath( $keyDbPath, $default );
	}

	/**
	 * 设置缓存数据
	 * @param mixed $value 存储数据
	 * @param int|null $expire 有效时间。[null][默认]跟随data id剩余时间
	 * @return void
	 */
	public function set( $value, $expire = null ) {
		$this->cacheClear();
		//
		$this->keyDbObj()->set( $value, $expire ?? $this->tokenObj->data()->getSupTime() );
	}

	/**
	 * 设置(路径)
	 * @param string $keyDbPath 数据路径（支持格式：1.PHP数组访问的格式，如：['a'][0]['b']， 2."->"分割，如：a->b->c）。
	 * @param mixed $value 数据
	 * @param int $expire 有效时间。[null][默认]跟随data id剩余时间
	 * @return void
	 */
	public function setOfPath( string $keyDbPath, $value, $expire = null ) {
		$this->cacheClear();
		//
		$this->keyDbObj()->setOfPath( $keyDbPath, $value, $expire ?? $this->tokenObj->data()->getSupTime() );
	}

	/**
	 * 设置(数组覆盖)
	 * @param array $keyDbPathArray 写入数据
	 * 如：[
	 * 		'a' => 1,
	 * 		'b' => [
	 * 			'c' => 2,
	 * 		],
	 * ]
	 * @param int $expire 有效时间。[null][默认]跟随data id剩余时间
	 * @return void
	 */
	public function setOfArray( array $keyDbPathArray, $expire = null ) {
		$this->cacheClear();
		//
		$this->keyDbObj()->setOfArray( $keyDbPathArray, $expire ?? $this->tokenObj->data()->getSupTime() );
	}

	/**
	 * 删除
	 * @return void
	 */
	public function del() {
		$this->cacheClear();
		//
		$this->keyDbObj()->del();
	}

	/**
	 * 删除缓存
	 * @param string $keyDbPath 数据路径（支持格式：1.PHP数组访问的格式，如：['a'][0]['b']， 2."->"分割，如：a->b->c）
	 * @return void
	 */
	public function delOfPath( string $keyDbPath ) {
		$this->keyDbObj()->delOfPath( $keyDbPath );
	}

	/**
	 * 缓存是否有效
	 * @param int $cacheTimeS
	 * @return bool
	 */
	private function cacheIsValid( int $cacheTimeS ) {
		if( $this->_lastKeyDbData === null || ( $this->_lastKeyDbDataTime + $cacheTimeS ) > com\Lib\Fun\Time::getTime() ){
			return false;
		}else{
			return true;
		}
	}

	/**
	 * 保存缓存
	 * @param $data
	 * @return void
	 */
	private function cacheSave( $data ) {
		$this->_lastKeyDbData = $data;
		$this->_lastKeyDbDataTime = com\Lib\Fun\Time::getTime();
	}

	/**
	 * 清除缓存
	 * @return void
	 */
	private function cacheClear(  ) {
		$this->_lastKeyDbData = null;
		$this->_lastKeyDbDataTime = 0;
	}

}
